iT邦幫忙

2024 iThome 鐵人賽

DAY 5
0
Modern Web

蓋一個自己的 Nuxt 3 UI Module系列 第 5

元件製作 select

  • 分享至 

  • xImage
  •  

昨天完成了表單常用的文字輸入框,感覺表單好像結束了呢!? 等等…還沒完呢! (我還有 25 天)
想想一個表單有一個以上的欄位要填寫,且有些欄位內容是固定的,如果需要使用者按照規定的格式填寫,難保會出現各種奇奇怪怪的寫法(x)
所以除了可以讓使用者自由輸入的輸入框以外,常見的還有下拉式選單 (select) ,下拉式選單能有效的提供使用者可用的選項,給予引導的效果,且在有大量資料需要呈現的情況下能讓畫面保持整潔喔~

一樣先思考 select 需要哪些狀態呢? 🤔

  • labelplaceholder 提示使用者輸入
  • disabled 不可選取狀態
  • 單選與多選狀態
  • <option>選項可選與不可選狀態
  • 錯誤狀態

簡單介紹到這邊,讓我們開始實作吧!

實作

  • 開始實作會發現…喔不! 標籤並沒有像 標籤提供 placeholder 這個 attribute,別擔心我們可以把第一個 option 借來當作 placeholder 用用…

    <script lang="ts" setup>
    
    export interface SelectPropsType {
      /** 預設內容文字 */
      placeholder?: string
      /** 標籤 */
      label?: string
      /** 標籤樣式 */
      classLabel?: string
      /** 輸入框樣式 */
      classInput?: string
      /** label for => select id */
      name: string
      /** v-modal */
      modelValue: any
      /** 錯誤訊息 */
      error?: string
      /** 是否不可選 */
      disabled?: boolean
      /** 是否複選 */
      multiple?: boolean
      /** 選項型別 */
      options: Array<{
        value: string
        label: string
        disabled?: boolean
      }>
    }
    
    withDefaults(defineProps<SelectPropsType>(), {
      label: '',
      classLabel: '',
      classInput: '',
      name: '',
      modelValue: '',
      error: '',
      description: '',
      size: '',
      options: () => [
        {
          value: '',
          label: 'Select Option'
        },
        {
          value: '',
          label: 'Select Option2'
        }
      ]
    })
    
    defineEmits(['update:modelValue'])
    </script>
    
    
    <template>
      <div
        class="fromGroup relative items-center"
        :class="{'has-error': error}"
      >
        <label
          class="flex input-label"
          :for="name"
        >
          <span :class="classLabel">{{ label }}</span>
        </label>
        <div
          class="relative"
        >
          <select
            v-bind="$attrs"
            :id="name"
            :name="name"
            :class="`${classInput} pr-8 input-control block w-full focus:outline-none min-h-[40px] `"
            :value="modelValue"
            :error="error"
            :disabled="disabled"
            :multiple="multiple"
            @input="$emit('update:modelValue', ($event.target as HTMLInputElement).value)"
          >
            <option
              v-if="placeholder"
              value=""
              selected
            >
              {{ placeholder }}
            </option>
              <option
                v-for="(item, index) in options"
                :key="index"
                :value="item.value"
                :disabled="item.disabled"
              >
                {{ item.label }}
              </option>
          </select>
        </div>
    
        <span
          v-if="error"
          class="absolute -bottom-6 right-0 mt-2  text-red-500 block text-sm"
        >{{ error }}</span>
      </div>
    </template>
    
    <style>
    select {
      @apply ...
    }
    option {
      @apply ...
    }
    </style>
    
    • 昨天有簡略的介紹了 defineModel,可以試試看把它改成 defineModel 的模式呦
  • 完成之後的樣子~

    <script lang="ts" setup>
    const selectValue = ref('')
    const options = [
      {
          value: '1',
          label: '魚'
        },
        {
          value: '2',
          label: '金魚'
        },
        {
          value: '3',
          label: '大頭魚',
          disabled: true
        }
    ]
    
    </script>
    <template>
      <div class="flex gap-x-4">   
        <Select :options="options" placeholder="- 請選擇魚 -" />
        <Select :options="options" disabled placeholder="- 請選擇魚 -" />
        <Select :options="options" disabled placeholder="- 請選擇魚 -" error="禁止撈魚"/>
      </div>
    </template>
    


上一篇
元件製作 input
下一篇
元件製作 checkbox
系列文
蓋一個自己的 Nuxt 3 UI Module16
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言